/* The file is saved in UTF-8 codepage.
 * Check: «Stereotype», Section mark-§, Copyright-©, Alpha-α, Beta-β, Smile-☺
 */
package cz.pecinovsky.english.lootp.shapes;


import cz.pecinovsky.english.lootp.utility.NamedColor;
import cz.pecinovsky.english.lootp.utility.IO_Test.IO;


import cz.pecinovsky.english.lootp.shapes.Canvas_Test.Canvas;
////////////////////////////////////////////////////////////////////////////////
//%%+  +++++ End of ignored starting test - place for imports +++++

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Shape;

import java.awt.geom.Rectangle2D;

import java.io.File;
import java.io.FileReader;
import java.io.Reader;

import java.util.Properties;

import javax.swing.JFrame;
import javax.swing.JPanel;


//%X+ xxxxx Start of the ovejumped text with declaration of the envelope xxxxx
/*******************************************************************************
 *<pre>
 * Předchozí:   Není - toto_je_nově_definovaná_třída
 *              Ttt v projektu Ppp
 * Následující: Prozatím není
 *
 * Projekt  Ppp
 *   + Přidáno
 *   - Odebráno
 *   ~ Změněno
 *</pre>
 *
 * @author Rudolf PECINOVSKÝ
 * @version 6.03.2017 — 2010-11-08
 */
public class Canvas_Test
{    private Canvas_Test() {}   static
////////////////////////////////////////////////////////////////////////////////
//%X- ----- End of the ovejumped text with declaration of the envelope -----

/*******************************************************************************
 * Třída {@code Canvas} slouží k jednoduchému kreslení na virtuální plátno.
 *
 * <p>
 * Třída neposkytuje veřejný konstruktor, protože chce, aby její instance
 * byla singleton, tj. aby se všechno kreslilo na jedno a to samé plátno.
 * Jediným způsobem, jak získat odkaz na instanci třídy Canvas,
 * je volaní statické metody {@link getCanvas()}.</p>.
 *
 * <p>
 * Aby bylo možno na plátno obyčejné kreslit a nebylo nutno kreslené objekty
 * přihlašovat, odmazané časti obrazců se automaticky neobnovují.
 * Je-li proto při smazání některého obrazce odmazána část jiného obrazce,
 * je třeba příslušný obrazec explicitně překreslit.</p>
 *
 * @author   Rudolf PECINOVSKÝ
 * @version 6.03.2017 — 2010-11-08
 */
public final class Canvas implements ICanvas
{
//== CONSTANT CLASS ATTRIBUTES =================================================
//== VARIABLE CLASS ATTRIBUTES =================================================

    /** Jediná instance třídy Canvas. */
    private static Canvas singleton; //Jediná instance

    static {
        String klíč = "rup.io.testmode";
        if (System.getProperty(klíč) != null &&
            Boolean.valueOf(System.getProperty(klíč)))
        {
            singleton = new Canvas(new PlátnoTestovací());
        }
        else {
            singleton = new Canvas(new PlátnoBěžné());
        }
    }



//== STATIC CONSTRUCTOR (CLASS INITIALIZER, STATIC INICITALIZING BLOCK) ======== 
//== CONSTANT INSTANCE ATTRIBUTES ==============================================

    /** Implemetnace {code IPlátno}, na kterou se deleguje.*/
    private final ICanvas delegát;

//== VARIABLE INSTANCE ATTRIBUTES ==============================================
//== CLASS GETTERS AND SETTERS =================================================
//== OTHER NON-PRIVATE CLASS METHODS ===========================================

    /***************************************************************************
     * Smaže plátno, přesněji smaže všechny obrazce na plátně.
     * Tato metoda by měla býr definována jako metodoa instance,
     * protože je instance singleton,
     * byla metoda pro snazší dostupnost definovaná jako metoda třídy.
     * Jinak by totiž bylo potřeba vytvořit před smazáním plátna jeho instanci.
     */
    public static void clearCanvas()
    {
        singleton.clear();
    }



//##############################################################################
//== CONSTUCTORS AND FACTORY METHODS ===========================================

    /***************************************************************************
     * Jediná metoda umožnující získat odkaz na instanci plátna.
     * Vrací vsak pokaždé odkaz na stejnou instanci, protože tato instance
     * je singleton. Pokud instance při volaní metody ještě neexistuje,
     * metoda instanci vytvoří.
     *
     * @return Odkaz na instanci třídy Canvas.
     */
    public static Canvas getCanvas()
    {
        singleton.setVisible(true);
        return singleton;
    }


    /***************************************************************************
     * Implicitní (a jediný) konstruktor - je volán pouze jednou.
     * @param delegát
     */
    @SuppressWarnings("serial")
    private Canvas(ICanvas delegát)
    {
        this.delegát = delegát;
    }



//== ABSTRACT METHODS ==========================================================
//== INSTANCE GETTERS AND SETTERS ==============================================

    /***************************************************************************
     * Vrátí aktuální barvu pozadí.
     *
     * @return   Nastavena color pozadí
     */
//%A+ <0    "To remove an editor warning
    @Override
//%A-
    public NamedColor getBackgroundColor()
    {
        return delegát.getBackgroundColor();
    }


    /***************************************************************************
     * Nastaví pro plátno barvu pozadí.
     *
     * @param color  Nastavovaná color pozadí
     */
//%A+ <0    "To remove an editor warning
    @Override
//%A-
    public void setBackgroundColor(NamedColor color)
    {
        delegát.setBackgroundColor(color);
    }


    /***************************************************************************
     * Nastaví pro plátno barvu popředí.
     *
     * @param  color  Nastavovaná color popředí
     */
//%A+ <0    "To remove an editor warning
    @Override
//%A-
    public void setForegroundColor(NamedColor color)
    {
        delegát.setForegroundColor(color);
    }


    /***************************************************************************
     * Vrátí šířku plátna.
     *
     * @return  Aktuální šířka plátna v bodech
     */
//%A+ <0    "To remove an editor warning
    @Override
//%A-
    public int getWidth()
    {
        return delegát.getWidth();
    }


    /***************************************************************************
     * Vrátí výšku plátna.
     *
     * @return  Aktuální výška plátna v bodech
     */
//%A+ <0    "To remove an editor warning
    @Override
//%A-
    public int getHeight()
    {
       return delegát.getHeight();
    }


    /***************************************************************************
     * Nastaví nový rozměr plátna zadáním jeho výsky a šířky.
     *
     * @param  šířka  Nova šířka plátna v bodech
     * @param  výška  Nová výška plátna v bodech
     */
//%A+ <0    "To remove an editor warning
    @Override
//%A-
    public void setSize(int šířka, int výška)
    {
       delegát.setSize(šířka, výška);
    }


    /***************************************************************************
     * Poskytuje informaci o aktuální viditelnosti okna.
     *
     * @return Je-li okno viditelné, vrací <b>true</b>, jinak vrací <b>false</b>
     */
//%A+ <0    "To remove an editor warning
    @Override
//%A-
    public boolean isVisible()
    {
        return delegát.isVisible();
    }


    /***************************************************************************
     * Nastaví viditelnost plátna.
     *
     * @param viditelné {@code true} má-li být plátno viditelné,
     *                  {@code false} má-li naopak přestat být viditelné
     */
//%A+ <0    "To remove an editor warning
    @Override
//%A-
    public void setVisible(boolean viditelné)
    {
        delegát.setVisible(viditelné);
    }



//== OTHER NON-PRIVATE INSTANCE METHODS ========================================

    /***************************************************************************
     * Smaže plátno, přesněji smaže všechny obrazce na plátně.
     */
//%A+ <0    "To remove an editor warning
    @Override
//%A-
    public void clear()
    {
        delegát.clear();
    }


    /***************************************************************************
     * Nakresli na plátno úsečku se zadanými krajními body.
     * Usedku vykreslí aktuální barvou popředí.
     *
     * @param  x1    x-ová souřadnice počátku
     * @param  y1    y-ová souřadnice počátku
     * @param  x2    x-ová souřadnice konce
     * @param  y2    x-ová souřadnice konce
     * @param  color NamedColor úsečky
     */
//%A+ <0    "To remove an editor warning
    @Override
//%A-
    public void drawLine(int x1, int y1, int x2, int y2, NamedColor color)
    {
       delegát.drawLine(x1, y1, x2, y2, color);
    }


    /***************************************************************************
     * Vypíše na plátno text aktuálním písmem a aktuální barvou popředí.
     *
     * @param text   Zobrazovaný text
     * @param x      x-ová souřadnice textu
     * @param y      y-ová souřadnice textu
     * @param color  NamedColor, kterou se zadaný text vypíše
     */
//%A+ <0    "To remove an editor warning
    @Override
//%A-
    public void drawString(String text, int x, int y, NamedColor color)
    {
        delegát.drawString(text, x, y, color);
    }


    /***************************************************************************
     * Smaže zadaný obrazec na plátně; obrazec vsak stalé existuje,
     * jenom není vidět. Smaže se totiž tak, že se nakreslí barvou pozadí.
     *
     * @param  obrazec   Obrazec, který má byt smazán
     */
//%A+ <0    "To remove an editor warning
    @Override
//%A-
    public void erase(Shape obrazec)
    {
        delegát.erase(obrazec);
    }


    /***************************************************************************
     * Nakreslí zadaný obrazec a vybarví jej barvou popředí plátna.
     *
     * @param  obrazec  Kreslený obrazec
     */
//%A+ <0    "To remove an editor warning
    @Override
//%A-
    public void fill(Shape obrazec)
    {
        delegát.fill(obrazec);
    }


    /***************************************************************************
     * Převede instanci na řetězec. Používá se především při ladění.
     *
     * @return Řetězcová reprezentace dané instance.
     */
    @Override
    public String toString()
    {
        return delegát.toString();
    }



//== PRIVATE AND AUXILIARY CLASS METHODS =======================================
//== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================
//== VNOŘENÉ A VNITŘNÍ TŘÍDY ===================================================

    /*******************************************************************************
     * Třída {@code Canvas} slouží k jednoduchému kreslení na virtuální plátno.
     *
     * <p>
     * Třída neposkytuje veřejný konstruktor, protože chce, aby její instance
     * byla singleton, tj. aby se všechno kreslilo na jedno a to samé plátno.
     * Jediným způsobem, jak získat odkaz na instanci třídy Canvas,
     * je volaní statické metody {@link getCanvas()}.</p>.
     *
     * <p>
     * Aby bylo možno na plátno obyčejné kreslit a nebylo nutno kreslené objekty
     * přihlašovat, odmazané časti obrazců se automaticky neobnovují.
     * Je-li proto při smazání některého obrazce odmazána část jiného obrazce,
     * je třeba příslušný obrazec explicitně překreslit.</p>
     */
    private static final class PlátnoBěžné implements ICanvas
    {
    //== CONSTANT CLASS ATTRIBUTES =================================================

        /** Titulek v záhlaví okna plátna. */
        private static final String TITULEK  = "Jednoduché plátno";

        /** Počáteční šířka plátna v bodech. */
        private static final int ŠÍŘKA_0 = 300;

        /** Počáteční výška plátna v bodech. */
        private static final int VÝŠKA_0 = 300;

        /** Počáteční color pozadí plátna. */
        private static final NamedColor POZADÍ_0 = NamedColor.CREAMY;



    //== VARIABLE CLASS ATTRIBUTES =================================================

        /** Jediná instance třídy Canvas. */
        private static PlátnoBěžné singleton = new PlátnoBěžné();  //Jediná instance



    //== STATIC CONSTRUCTOR (CLASS INITIALIZER, STATIC INICITALIZING BLOCK) ======== 
    //== CONSTANT INSTANCE ATTRIBUTES ==============================================
    //== VARIABLE INSTANCE ATTRIBUTES ==============================================

        //Z venku neovlivnitelné Atributy pro zobrazeni plátna v aplikačním okně

            /** Aplikační okno animacniho plátna. */
            private JFrame okno;

            /** Instance lokální třídy, která je zřízena proto, aby odstínila
             *  metody svého rodiče JPanel. */
            private JPanel vlastníPlátno;

            /** Vše se kreslí na obraz - ten se snadněji překreslí. */
            private Image obrazPlátna;

            /** Kreslítko získané od obrazu plátna, na nějž se vlastně kreslí. */
            private Graphics2D painter;

    //        /** Rozdíl mezi tlouštkou rámečku okna ohlašovanou před a po
    //         *  volání metody {@link #setResizable(boolean)}.
    //         *  Tento rozdíl ve Windows ovlivňuje nastavení velikosti a pozice.
    //         *  Při {@code setResizable(true)} jsou jeho hodnoty větší,
    //         *  a proto se spočte se jako "true" - "false". */
    //        Insets insetsDif;


        //Přímo ovlivnitelné atributy
            private NamedColor barvaPozadí;
            private int šířka;
            private int výška;

            /** Pozice plátna na obrazovace - při používání více obrazovek
             *  je občas třeba ji po zviditelnění obnovit. */
            Point pozice = new Point(0, 0);



    //== CLASS GETTERS AND SETTERS =================================================
    //== OTHER NON-PRIVATE CLASS METHODS ===========================================

        /***************************************************************************
         * Smaže plátno, přesněji smaže všechny obrazce na plátně.
         * Tato metoda by měla býr definována jako metodoa instance,
         * protože je instance singleton,
         * byla metoda pro snazší dostupnost definovaná jako metoda třídy.
         * Jinak by totiž bylo potřeba vytvořit před smazáním plátna jeho instanci.
         */
        public static void smažPlátno()
        {
            singleton.clear();
        }



    //##############################################################################
    //== CONSTUCTORS AND FACTORY METHODS ===========================================

        /***************************************************************************
         * Jediná metoda umožnující získat odkaz na instanci plátna.
         * Vrací vsak pokaždé odkaz na stejnou instanci, protože tato instance
         * je singleton. Pokud instance při volaní metody ještě neexistuje,
         * metoda instanci vytvoří.
         *
         * @return Odkaz na instanci třídy Canvas.
         */
        public static PlátnoBěžné getPlátno()
        {
            singleton.setVisible(true);
            return singleton;
        }


        /***************************************************************************
         * Implicitní (a jediný) konstruktor - je volán pouze jednou.
         */
        @SuppressWarnings("serial")
        private PlátnoBěžné()
        {
            konfiguraceZeSouboru();
            okno  = new JFrame();          //Vytvoří nové aplikační okno
            okno.setLocation(pozice);
            okno.setTitle(TITULEK);

            //Zavřením okna se zavře celá aplikace
            okno.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            vlastníPlátno = new JPanel()
            {   /** Povinně překrývaná abstraktní metoda třídy JPanel. */
                @Override
                public void paintComponent(Graphics g) {
                    g.drawImage(obrazPlátna, 0, 0, null);
                }
            };
            okno.setContentPane(vlastníPlátno);
            barvaPozadí = POZADÍ_0;

            setRozměrSoukr(ŠÍŘKA_0, VÝŠKA_0);  //Připraví a vykreslí prázdné plátno
            IO.Correction.windowLocation(okno);
            připravObrázek();
            clear();

            IO.setDialogsPosition(pozice.x, pozice.y + okno.getSize().height);
        }



    //== ABSTRACT METHODS ==========================================================
    //== INSTANCE GETTERS AND SETTERS ==============================================

        /***************************************************************************
         * Vrátí aktuální barvu pozadí.
         *
         * @return   Nastavena color pozadí
         */
        @Override public NamedColor getBackgroundColor()
        {
            return barvaPozadí;
        }


        /***************************************************************************
         * Nastaví pro plátno barvu pozadí.
         *
         * @param color  Nastavovaná color pozadí
         */
        @Override public void setBackgroundColor(NamedColor color)
        {
            barvaPozadí = color;
            painter.setBackground(barvaPozadí.getAwtColor());
            clear();
        }


        /***************************************************************************
         * Nastaví pro plátno barvu popředí.
         *
         * @param  color  Nastavovaná color popředí
         */
        @Override public void setForegroundColor(NamedColor color)
        {
            painter.setColor(color.getAwtColor());
        }


        /***************************************************************************
         * Vrátí šířku plátna.
         *
         * @return  Aktuální šířka plátna v bodech
         */
        @Override public int getWidth()
        {
            return šířka;
        }


        /***************************************************************************
         * Vrátí výšku plátna.
         *
         * @return  Aktuální výška plátna v bodech
         */
        @Override public int getHeight()
        {
            return výška;
        }


        /***************************************************************************
         * Nastaví nový rozměr plátna zadáním jeho výsky a šířky.
         *
         * @param  šířka  Nova šířka plátna v bodech
         * @param  výška  Nová výška plátna v bodech
         */
        @Override public void setSize(int šířka, int výška)
        {
            setRozměrSoukr(šířka, výška);
    //        obrazPlátna = vlastníPlátno.createImage(šířka+2, výška+2);
    //        painter = (Graphics2D)obrazPlátna.getGraphics();
    //        painter.setBackground(barvaPozadí.getAwtColor());
            setVisible(true);
            připravObrázek();
            clear();
        }


        /***************************************************************************
         * Poskytuje informaci o aktuální viditelnosti okna.
         *
         * @return Je-li okno viditelné, vrací <b>true</b>, jinak vrací <b>false</b>
         */
        @Override public boolean isVisible()
        {
            return okno.isVisible();
        }


        /***************************************************************************
         * Nastaví viditelnost plátna.
         *
         * @param viditelné {@code true} má-li být plátno viditelné,
         *                  {@code false} má-li naopak přestat být viditelné
         */
        @Override public void setVisible(boolean viditelné)
        {
            boolean změna = (isVisible() != viditelné);
            if (změna) {
                pozice = okno.getLocation();
                okno.setVisible(viditelné);
                if (viditelné)
                {
                    //Při více obrazovkách po zviáditelnění blbne =>
                    okno.setLocation(pozice);   //je třeba znovu nastavit pozici
                    okno.setAlwaysOnTop(true);
                    okno.toFront();
                    okno.setAlwaysOnTop(false);
                }
            }
        }



    //== OTHER NON-PRIVATE INSTANCE METHODS ========================================

        /***************************************************************************
         * Smaže plátno, přesněji smaže všechny obrazce na plátně.
         */
        @Override public void clear()
        {
            erase(new Rectangle2D.Double(0, 0, šířka, výška));
        }


        /***************************************************************************
         * Nakresli na plátno úsečku se zadanými krajními body.
         * Usedku vykreslí aktuální barvou popředí.
         *
         * @param  x1    x-ová souřadnice počátku
         * @param  y1    y-ová souřadnice počátku
         * @param  x2    x-ová souřadnice konce
         * @param  y2    x-ová souřadnice konce
         * @param  color NamedColor úsečky
         */
        @Override public void drawLine(int x1, int y1, int x2, int y2, NamedColor color)
        {
            setForegroundColor(color);
            painter.drawLine(x1, y1, x2, y2);
            vlastníPlátno.repaint();
        }


        /***************************************************************************
         * Vypíše na plátno text aktuálním písmem a aktuální barvou popředí.
         *
         * @param text   Zobrazovaný text
         * @param x      x-ová souřadnice textu
         * @param y      y-ová souřadnice textu
         * @param color  NamedColor, kterou se zadaný text vypíše
         */
        @Override public void drawString(String text, int x, int y, NamedColor color)
        {
            setForegroundColor(color);
            painter.drawString(text, x, y);
            vlastníPlátno.repaint();
        }


        /***************************************************************************
         * Smaže zadaný obrazec na plátně; obrazec vsak stalé existuje,
         * jenom není vidět. Smaže se totiž tak, že se nakreslí barvou pozadí.
         *
         * @param  obrazec   Obrazec, který má byt smazán
         */
        @Override public void erase(Shape obrazec)
        {
            Color original = painter.getColor();
            painter.setColor(barvaPozadí.getAwtColor());
            painter.fill(obrazec);       //Smaže jej vyplněním barvou pozadí
            painter.setColor(original);
            vlastníPlátno.repaint();
        }


        /***************************************************************************
         * Nakreslí zadaný obrazec a vybarví jej barvou popředí plátna.
         *
         * @param  obrazec  Kreslený obrazec
         */
        @Override public void fill(Shape obrazec)
        {
            painter.fill(obrazec);
            vlastníPlátno.repaint();
        }


        /***************************************************************************
         * Převede instanci na řetězec. Používá se především při ladění.
         *
         * @return Řetězcová reprezentace dané instance.
         */
        @Override public String toString()
        {
            return this.getClass().getName() +
                "(" + šířka + "×" + výška +
                " bodů, barvaPozadí=" + barvaPozadí + ")";
        }



    //== PRIVATE AND AUXILIARY CLASS METHODS =======================================
    //== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================

        /***************************************************************************
         * Inicializuje některé parametry z konfiguračního souboru.
         * Tento soubor je umístěn v domovském adresáři uživatele
         * ve složce {@code .rup} v souboru {@code bluej.properties}.
         */
        private void konfiguraceZeSouboru() {
            Properties sysProp = System.getProperties();
            String     userDir = sysProp.getProperty("user.home");
            File       rupFile = new File(userDir, ".rup/bluej.properties");
            Properties rupProp = new Properties();
            try {
                Reader reader = new FileReader(rupFile);
                rupProp.load(reader);
                reader.close();
                String sx = rupProp.getProperty("canvas.x");
                String sy = rupProp.getProperty("canvas.y");
                int x = Integer.parseInt(rupProp.getProperty("canvas.x"));
                int y = Integer.parseInt(rupProp.getProperty("canvas.y"));
                pozice = new Point(x, y);
            }catch(Exception e)  {
                pozice = new Point(0, 0);
            }
        }


        /***************************************************************************
         * Připraví obrázek, do nějž se budou všechny tvary kreslit.
         */
        private void připravObrázek()
        {
            obrazPlátna = vlastníPlátno.createImage(šířka, výška);
            painter = (Graphics2D)obrazPlátna.getGraphics();
            painter.setColor(barvaPozadí.getAwtColor());
            painter.fillRect(0, 0, šířka, výška);
            painter.setColor(Color.black);
        }


        /***************************************************************************
         * Nastaví zadaný rozměr plátna, ale pouze ten.
         * Soufkorá verze určená pro konstruktor.
         * Veřejná verze přidává ještě zviditelnění plátna a přípravu obrázku.
         *
         * @param šířka  Nastavovaná bodová šířka plátna
         * @param výška  Nastavovaná bodová výška plátna
         */
        private void setRozměrSoukr(int šířka, int výška)
        {
            boolean upravit;
            Dimension dim;
            Insets    ins;
            do {
                this.šířka = šířka;
                this.výška = výška;
                okno.setResizable(true);
                vlastníPlátno.setPreferredSize(new Dimension(šířka, výška));
                okno.pack();
                dim = okno.getSize();
                ins = okno.getInsets();
    //            IO.inform(
    //                   "Nastavuju: šířka=" + šířka + ", výška=" + výška +
    //                 "\nMám: width=" + dim.width + ", height=" + dim.height +
    //                 "\nleft=" + ins.left + ", right=" + ins.right +
    //                 "\n top=" + ins.top + ", bottom=" + ins.bottom);
                upravit = false;
                if (šířka < (dim.width - ins.left - ins.right)) {
                    šířka  = dim.width - ins.left - ins.right + 2;
                    upravit= true;
                }
                if (výška < (dim.height - ins.top - ins.bottom)) {
                    výška  = dim.height - ins.top - ins.bottom;
                    upravit= true;
                }
            } while (upravit);

            okno.setResizable(false);    //Není možné měnit rozměr pomocí myši
            IO.Correction.windowSize(okno);
        }



    //== VNOŘENÉ A VNITŘNÍ TŘÍDY ===================================================
    //== TESTOVACÍ TŘÍDY A METODY ==================================================
    }


///#############################################################################
///#############################################################################
///#############################################################################


    /*******************************************************************************
     * Testovací implementace rozhraní {@code IPlátno}, která ignoruje všechny
     * volání metod, pouze zaznamenává počet jejich volání.
     */
    private static final class PlátnoTestovací implements ICanvas
    {
    //== CONSTANT CLASS ATTRIBUTES =================================================
    //== VARIABLE CLASS ATTRIBUTES =================================================
    //== STATIC CONSTRUCTOR (CLASS INITIALIZER, STATIC INICITALIZING BLOCK) ======== 
    //== CONSTANT INSTANCE ATTRIBUTES ==============================================
    //== VARIABLE INSTANCE ATTRIBUTES ==============================================
    //== CLASS GETTERS AND SETTERS =================================================
    //== OTHER NON-PRIVATE CLASS METHODS ===========================================

    //##############################################################################
    //== CONSTUCTORS AND FACTORY METHODS ===========================================

        PlátnoTestovací()
        {
        }

    //== ABSTRACT METHODS ==========================================================
    //== INSTANCE GETTERS AND SETTERS ==============================================

        @Override public NamedColor getBackgroundColor() {
            přidejVoláníMetody("getBarvaPozadí");
            return NamedColor.NO;
        }
        @Override public void setBackgroundColor(NamedColor color) {
            přidejVoláníMetody("setBarvaPozadí_Barva");
        }
        @Override public void setForegroundColor(NamedColor color) {
            přidejVoláníMetody("setBarvaPopředí_Barva");
        }
        @Override public int getWidth() {
            přidejVoláníMetody("getŠířka");
            return 0;
        }
        @Override public int getHeight() {
            přidejVoláníMetody("getVýška");
            return 0;
        }
        @Override public void setSize(int šířka, int výška) {
            přidejVoláníMetody("setRozměr_int_int");
        }
        @Override public boolean isVisible() {
            přidejVoláníMetody("isViditelné");
            return true;
        }
        @Override public void setVisible(boolean viditelné) {
            přidejVoláníMetody("setViditelné_boolean");
        }


    //== OTHER NON-PRIVATE INSTANCE METHODS ========================================

        @Override public void clear() {
            přidejVoláníMetody("smaž");
        }
        @Override public void drawLine(int x1, int y1, int x2, int y2,
                                         NamedColor color) {
            přidejVoláníMetody("kresliČáru_int_int_int_int_Barva");
        }
        @Override public void drawString(String text, int x, int y,
                                           NamedColor color) {
            přidejVoláníMetody("kresliString_String_int_int_Barva");
        }
        @Override public void erase(Shape obrazec) {
            přidejVoláníMetody("smaž_Shape");
        }
        @Override public void fill(Shape obrazec) {
            přidejVoláníMetody("zaplň_Shape");
        }



    //== PRIVATE AND AUXILIARY CLASS METHODS =======================================

        /***************************************************************************
         * Zaznamená volání metody do systémových proměnných. Systémové proměnné
         * začánají na {@code rup.io.method.} a následuje označení metody
         * ve tvaru {@code jménoMetody_typParametru1_typParametru2}
         *
         * @param metoda   Označení metody
         */
        private static void přidejVoláníMetody(String metoda)
        {
            String kód = "rup.io.method." + metoda;
            String hodnota = System.getProperty(kód, "0");
            int počet = Integer.valueOf(hodnota);
            počet++;
            System.setProperty(kód, "" + počet);
        }

    //== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================
    //== VNOŘENÉ A VNITŘNÍ TŘÍDY ===================================================
    //== TESTOVACÍ TŘÍDY A METODY ==================================================
    }



//== TESTOVACÍ TŘÍDY A METODY ==================================================
}

///#############################################################################
///#############################################################################
///#############################################################################



/***************************************************************************
 * Rozhraní {@code IPlátno} deklaruje kompletní sadu metod
 * implementovaných třídou {@code Canvas}.
 * Představuje společného rodiče výkonné a testovací třídy,
 * tj. třídy {@code PlátnoBěžné} a třídy {@code PlátnoTestovací}.
 */
interface ICanvas
{
//== KONSTANTY =============================================================
//== DEKLAROVANÉ METODY ====================================================

    public NamedColor   getBackgroundColor();
    public void     setBackgroundColor(NamedColor color);
    public void     setForegroundColor(NamedColor color);
    public int      getWidth();
    public int      getHeight();
    public void     setSize(int width, int height);
    public boolean  isVisible();
    public void     setVisible(boolean viditelné);
    public void     clear();
    public void     drawLine(int x1, int y1, int x2, int y2, NamedColor color);
    public void     drawString(String text, int x, int y, NamedColor color);
    public void     erase(Shape obrazec);
    public void     fill(Shape obrazec);



//== ZDĚDĚNÉ METODY ========================================================
//== INTERNÍ DATOVÉ TYPY ===================================================
    }

//%%- ---- Start of the ovejumped text with closing of the envelope ----
////////////////////////////////////////////////////////////////////////////////
//== TESTING CLASSES AND METHODS ===============================================

    /***************************************************************************
     * Test method.
     */
    public static void test()
    {
//        Run.tests(Test.class,
//                new TearDown(),
//                "testFixture",
//                "");
        IO.inform("Až se pokocháš, stiskni OK");
        System.exit(0);
    }
    /** @param args Parametry příkazového řádku - nepoužívané. */
    public static void main(String[] args)  {  test();  }
}
